﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace nameero.util
{
    class AlphaBetaMinimax
    {
        //maksimalna dubina....mijenjamo po potrebi
        const int maxDepth = 8;

        private static Boolean player1turn;

        static int nodesEven;
        static int nodesOdd;
        //koristiti za testiranje

        /*static void Main (string []args)
        {
            Node root = new Node();
            root.setGameState(new GameState());
            //createTree(root);
            alphaBetaMiniMax(root, -1000, 1000);
            foreach (Node child in root.getChildren())
            {
                Console.WriteLine("alfabetavrijednost "+child.getAlphaBetaValue());
            }

        }*/

        public static void alphaBetaMiniMax(Node node, Boolean p1t, int alpha, int beta)
        {
            player1turn = p1t;
            DateTime start = DateTime.Now;
            nodesEven = 0;
            nodesOdd = 0;
            //createTree(node);
            int result = minimaxEven(node, alpha, beta);
            node.setAlphaBetaValue(result);
            //Console.WriteLine("reza je " + result);
            TimeSpan duration = DateTime.Now - start;
            Console.WriteLine("Obradjeno {0} even i {1} odd cvorova u {2}", nodesEven, nodesOdd, duration);
        }

        static int minimaxEven(Node n, int alpha, int beta)
        {
            nodesEven++;
            if (n.getDepth() == maxDepth)
            {
                int eval = n.getGameState().getHeuristics().get3PhaseHeuristic(true);
                n.setAlphaBetaValue(eval);
                return eval;
            }

            int m = alpha;
            GameState gs = n.getGameState();
            // potezi trenutnog igraca
            LinkedList<GameState> possibleMoves = gs.getAllMoves(player1turn);
            if (possibleMoves.Count == 0)
            {
                n.setAlphaBetaValue(Int32.MinValue);
                return Int32.MinValue;
            }
            //Console.WriteLine("vrijednost " + n.getGameState().evaluate() + " dubina " + n.getDepth() + " br dece " + possibleMoves.Count);

            //int nodeEvaluation = Int32.MinValue;
            //System.Console.WriteLine("Nalazim se u čvoru dubine " + n.getDepth());
            foreach (GameState g in possibleMoves)
            {
                // ako lista nije prazna, provjeri je li prijelaz u stanje u listi odstranjenih
                // ako jest, preskoči i ne dodaj kao dijete
                Node node = new Node(n);
                node.setGameState(g);
                n.addChild(node);
                m = Math.Max(m, minimaxOdd(node, m, beta));
                node.setAlphaBetaValue(m);
                if (m >= beta)
                {
                    return m;
                }
            }
            return m;
        }

        static int minimaxOdd(Node n, int alpha, int beta)
        {
            nodesOdd++;
            if (n.getDepth() == maxDepth)
            {
                int eval = n.getGameState().getHeuristics().get3PhaseHeuristic(false);
                n.setAlphaBetaValue(eval);
                return eval;
            }
            GameState gs = n.getGameState();
            // potezi protivnika
            LinkedList<GameState> possibleMoves = gs.getAllMoves(!player1turn);
            if (possibleMoves.Count == 0)
            {
                n.setAlphaBetaValue(Int32.MaxValue);
                return Int32.MaxValue;
            }
            //int nodeEvaluation = Int32.MaxValue;
            // Console.WriteLine("vrijednost " + n.getGameState().evaluate() + " dubina " + n.getDepth()+ " br dece "+possibleMoves.Count) ;

            int m = beta;
            foreach (GameState g in possibleMoves)
            // System.Console.WriteLine("Nalazim se u čvoru dubine " + n.getDepth());
            {
                Node node = new Node(n);
                node.setGameState(g);
                n.addChild(node);
                m = Math.Min(m, minimaxEven(node, alpha, m));
                node.setAlphaBetaValue(m);
                if (m <= alpha)
                {
                    return m;
                }

            }
            return m;
        }
    }
}
